﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.Diagnostics;

namespace Mongaba.Core.Listeners
{
    internal class ResponseListener
    {
        static int ListenerPort = Utilities.ProcessResponseListenerPort;
        static int SenderPort = Utilities.CoordinatorRequestListenerPort;

        /// <summary>
        /// Evento disparado no recebimento de nova string
        /// </summary>
        public static event EventHandler ResponseReceivedEvent;

        /// <summary>
        /// Retorna o conjunto de Strings recebidos da seção até o momento.
        /// </summary>
        /// <returns></returns>
        public static IPAddress[] GetResponseList()
        {
            return _responseList.ToArray();
        }

        static List<IPAddress> _responseList = new List<IPAddress>();

        static byte[] buf = new byte[65000];

        static void Receive(IAsyncResult ar)
        {
            try
            {
                Socket listener = ar.AsyncState as Socket;
                int bytesReceived = listener.EndReceive(ar);
                string str = Encoding.ASCII.GetString(buf, 0, bytesReceived);
                _responseList.Add(IPAddress.Parse(str));
                if (ResponseReceivedEvent != null)
                {
                    ResponseReceivedEvent(null, null);
                }
                Console.WriteLine(String.Format("Nova mensagem recebida: {0}.",str));
                WaitForData();
            }
            catch (ObjectDisposedException)
            {
                return;
            }
            
        }

        static  void WaitForData()
        {
            try
            {
                sckListenter.BeginReceive(buf, 0, buf.Length, SocketFlags.None, new AsyncCallback(Receive), sckListenter);
            }
            catch (ObjectDisposedException)
            {
                return;
            }
            catch (NullReferenceException)
            {
                return;
            }
        }

      
        static Socket sckListenter;


        public static void Start()
        {
            _isListening = true;
            _responseList.Clear();
            sckListenter = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            sckListenter.Bind(new IPEndPoint(Utilities.HostIp, ListenerPort));           
            WaitForData();
            Console.WriteLine("Escuta do processo começou.");
        }

        public static void Refresh()
        {
            _responseList.Clear();
            SendBroadCast();
        }

        static void SendBroadCast()
        {
            IPAddress ip = Utilities.HostIp;
            //definiçao da mensagem de retorno como seu própio IP.
            string strMessage = Utilities.HostIp.ToString();
            //transformando a string em sequência de bytes para envio via UDP.
            byte[] data = Encoding.ASCII.GetBytes(strMessage);
            //Definindo o socket de resposta.
            Socket sckResponse = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            //Conectando ao host de resposta.
            sckResponse.Connect(new IPEndPoint(IPAddress.Broadcast, SenderPort));
            //Enviando os dados.
            sckResponse.Send(data);
            //Fechando o socket.
            sckResponse.Close();
            Console.WriteLine("Envio de broadcast terminado.");
        }

        /// <summary>
        /// Termina o serviço de escuta do processo.
        /// </summary>
        public static void Stop()
        {
            if (sckListenter != null)
            {
                _isListening = false;
                sckListenter.Close(1);
                sckListenter = null;
                Console.WriteLine("Escuta do processo terminou.");
            }
        }


        static bool _isListening = false;
        public static bool IsListening
        {
            get { return _isListening; }
        }


    }
}
